#include "PlayerBase.h"
#include "StackTrace.h"
#include "RoomBase.h"
#include "GateSessionBase.h"
#include "StackTrace.h"
#include "GateSessionManager.h"
#include "LogEx.h"
#include "Hall.h"
#include "Utils.h"
#include "ActivityConfig.h"
#include "msg_center.h"
#include "msg_roomcenter.h"
#include "ActivityManager.h"

using namespace std;

CPlayerBase::CPlayerBase() : 
	m_gateid(0),
	m_clientid(0),
	m_userid(0),
	m_state(E_PlayerState_Idle),
	m_room(NULL)
{
}

CPlayerBase::~CPlayerBase()
{
}

void CPlayerBase::Init()
{
    m_state = E_PlayerState_Idle;
	m_room = NULL;
	m_seatno = INVALID_SEAT;
    m_addiStatus = 0;
	
    m_action = ACTION_INVALID;
    m_actionExpireTime = 0;

	m_readyExpireTime = 0;
    
    m_winData = 0;
    m_getDate = 0;
    m_winCount = 0;
    m_offlineTime = 0;
    m_locationInfo = "{}";
    m_gameTimes = 0; 
    m_useItemLastTime = 0;

    m_moreAction.clear();
    
    m_dismissState = commonproto::E_FRoomEnd_Normal;
}

void CPlayerBase::OnLeaveHall()
{
    char sql[1024] = {0};
    sprintf( sql, "UPDATE tb_user_basic SET exp=%llu WHERE userid=%llu;",
        m_basicInfo.exp, UserId() );
    bool ret = CHall::Instance().NotifyDBProxyExecSQL( sql, UserId() );
    LOG_DEBUG( "[%s] sql[%s] ret[%d]", __FUNCTION__, sql, ret?1:0 );
}

u64 CPlayerBase::GateId() const
{
	return m_gateid;
}

u64 CPlayerBase::ClientId() const
{
	return m_clientid;
}

u64 CPlayerBase::UserId() const
{
	return m_userid;
}

CPlayerBase::EPlayerState CPlayerBase::State() const
{
	return m_state;
}

void CPlayerBase::SetState(CPlayerBase::EPlayerState state)
{
	m_state = state;
}

void CPlayerBase::InitPlayer(u64 gateid, u64 clientid, u64 userid)
{
	m_gateid = gateid;
	m_clientid = clientid;
	m_userid = userid;
    Init();
}

void CPlayerBase::ResetPlayer(u64 gateid, u64 clientid)
{
	m_gateid = gateid;
	m_clientid = clientid;
}

void CPlayerBase::SendMsg(s32 msgid, const IMessage &msg)
{
	LOG_DEBUG( "SendMsg to player. msgid[%d] userid[%llu][%llu,%llu]", msgid, UserId(), GateId(), ClientId() );
    CHall::Instance().SendMsg( GateId(), ClientId(), msgid, msg );
}

void CPlayerBase::Close()
{
	CHall::Instance().UpdateGameTimes2DBProxy(NULL, this, 0);	
    CHall::Instance().Close( GateId(), ClientId() );
}

s32 CPlayerBase::GetExp(s64 score)
{
    s32 exp = 0;
    if( CHall::Instance().IsFriendMode() )
    {
        if( score > 0 ) exp = 1;
    }
    else
    {
        if( score >= 100 ) exp = 2;
        else if( score >= 1000 ) exp = 4;
        else if( score >= 10000 ) exp = 6;
        else if( score >= 100000 ) exp = 8;
        else if( score >= 1000000 ) exp = 10;
    }
    return exp;
}

void CPlayerBase::EnterRoom(CRoomBase &room, s32 seatno)
{
	SetState( CPlayerBase::E_PlayerState_WaitInRoom );
	m_room = &room;
	m_seatno = seatno;

    if( m_seatno != INVALID_SEAT )
    {
        CHall::Instance().NotifyRoomCenterUserInOut( room.Id(), UserId(), roomcenter::User_In, 
            m_basicInfo.uuid, m_basicInfo.nickname );
    }

	OnEnterRoom();
}

void CPlayerBase::DoLeaveRoom()
{
	SetState( CPlayerBase::E_PlayerState_Hall );
	CRoomBase *room = GetRoom();
	SELF_ASSERT( room, return; );

    if( m_seatno != INVALID_SEAT )
    {
        CHall::Instance().NotifyRoomCenterUserInOut( room->Id(), UserId(), roomcenter::User_Out,
            m_basicInfo.uuid, m_basicInfo.nickname );
    }

	m_room = NULL;
	m_seatno = INVALID_SEAT;
}

void CPlayerBase::LeaveRoom()
{
	DoLeaveRoom();
	OnLeaveRoom();
}

void CPlayerBase::SitDown(s32 seatno)
{
    m_seatno = seatno;
    OnSitDown();
}

void CPlayerBase::StandUp()
{
    m_seatno = INVALID_SEAT;
	SetState( CPlayerBase::E_PlayerState_WaitInRoom );
    OnStandUp();
}

CRoomBase* CPlayerBase::GetRoom()
{
	return m_room;
}

s32 CPlayerBase::GetSeatNo()
{
	return m_seatno;
}

void CPlayerBase::ResetSeatNo(s32 seatno)
{
    m_seatno = seatno;
}

bool CPlayerBase::IsBeholder()
{
    return ( GetSeatNo() == -1 );
}

void CPlayerBase::SetOffline(bool offline)
{
    if( offline )
    {
        m_addiStatus |= ADDI_STATUS_OFFLINE;
        m_offlineTime = TIME_NOW;
    }
    else
    {
        m_addiStatus &= ~ADDI_STATUS_OFFLINE;
        m_offlineTime = 0;
    }
}

void CPlayerBase::SetTrusteeship(bool trusteeship)
{
    if( trusteeship )
    {
        m_addiStatus |= ADDI_STATUS_TRUSTEESHIP;
    }
    else
    {
        m_addiStatus &= ~ADDI_STATUS_TRUSTEESHIP;
    }
}

bool CPlayerBase::IsOffline()
{
    return ( (m_addiStatus & ADDI_STATUS_OFFLINE) != 0 );
}

bool CPlayerBase::IsTrusteeship()
{
    return ( (m_addiStatus & ADDI_STATUS_TRUSTEESHIP) != 0 );
}

bool CPlayerBase::IsRobot()
{
    return (m_type == 99);
}

void CPlayerBase::SetAction(s32 action, u64 actionExpire)
{
    m_action = action;
    m_actionExpireTime = actionExpire;
}

s32 CPlayerBase::GetAction()
{
	return m_action;
}

bool CPlayerBase::IsActionValid()
{
	return (m_action != ACTION_INVALID);
}

void CPlayerBase::CleanAction()
{
    SetAction( ACTION_INVALID, 0 );
}

s32 CPlayerBase::GetActionLeftSec()
{
	return (s32)(m_actionExpireTime - TIME_NOW);
}

void CPlayerBase::ResetActionExpire(u64 actionExpire)
{
    if( IsActionValid() )
    {
        m_actionExpireTime = actionExpire;
    }
}

bool CPlayerBase::IsActionTimeOut(u64 now)
{
    if( m_action != ACTION_INVALID )
    {
        return (now >= m_actionExpireTime);
    }
    return false;
}

void CPlayerBase::ActionTimeOut()
{
    // 注意这里先清action,在timeout中有可能会给player加新的action
    s32 action = m_action; 
    CleanAction();
    OnActionTimeOut( action );
}

void CPlayerBase::AddMoreAction(s32 action, u64 actionExpire)
{
    std::map<s32, u64>::iterator it = m_moreAction.find( action );
    if( it != m_moreAction.end() )
    {
        it->second = actionExpire;
    }
    else
    {
        m_moreAction[ action ] = actionExpire;
    }
}

void CPlayerBase::DelMoreAction(s32 action)
{
    std::map<s32, u64>::iterator it = m_moreAction.find( action );
    if( it != m_moreAction.end() )
    {
        m_moreAction.erase( it );
    }
}

bool CPlayerBase::HasMoreAction(s32 action)
{
    std::map<s32, u64>::iterator it = m_moreAction.find( action );
    if( it != m_moreAction.end() )
    {
        return true;
    }
    return false;
}

void CPlayerBase::CheckMoreActionTimeOut(u64 now)
{
    std::map<s32, u64>::iterator it = m_moreAction.begin();
    for( ; it != m_moreAction.end(); )
    {
        if( now >= it->second )
        {
            s32 action = it->first;
            m_moreAction.erase( it++ );
            if( action == commonproto::Action_AgreeDismissFriendRoom )
            {
                _TimeOutAgreeDismissFriendRoom();
            }
            else
            {
                OnActionTimeOut( action );
            }
        }
        else
        {
            ++it;
        }
    }
}

void CPlayerBase::DumpAllActions(std::vector<publicproto::ActionData> &actions)
{
    if( IsActionValid() )
    {
        publicproto::ActionData d;
        d.action = GetAction();
        d.leftsec = GetActionLeftSec();
        actions.push_back( d );
    }
    u64 now = TIME_NOW;
    std::map<s32, u64>::iterator it = m_moreAction.begin();
    for( ; it != m_moreAction.end(); ++it )
    {
        publicproto::ActionData d;
        d.action = it->first;
        d.leftsec = (s32)(it->second - now);
        actions.push_back( d );
    }
}

void CPlayerBase::SetReadyExpire(u64 readyExpire)
{
	m_readyExpireTime = readyExpire;
}

bool CPlayerBase::IsReadyExpire(u64 now)
{
	return (State() == E_PlayerState_WaitInRoom && 
		!IsBeholder() && 
		now >= m_readyExpireTime); 
}

void CPlayerBase::LoginResult(dbcommon::DBUserBasicInfo &basicinfo, publicproto::GameData &gamedata)
{
    m_gamedata = gamedata;
    _CopyDBUserBasicInfo( basicinfo );
    
    // 在到center获取下money信息
    CHall::Instance().GetUserMoneyInfo( *this );
	    
    LOG_DEBUG( "[%s][%s][%d] userid[%llu] d1[%llu,%llu,%llu] score[%lld,%lld] [%lld]", 
        __FILE__, __FUNCTION__, __LINE__,
        UserId(), m_gamedata.wincount, m_gamedata.lostcount, m_gamedata.drawcount,
        m_gamedata.winscore, m_gamedata.lostscore, m_gamedata.tfwincount );
}

void CPlayerBase::UpdateMoney(s32 type, s64 count, s32 reason)
{
    if( type < 0 || type >= commonproto::E_MoneyType_Count )
    {
	    LOG_ERROR( "[%s][%s][%d] userid[%llu] update[%d][%lld] reason[%d]", 
            __FILE__, __FUNCTION__, __LINE__,
            UserId(), type, count, reason );
        return;
    }
    
    s64 old = m_basicInfo.money[type];
    m_basicInfo.money[type] += count;
    if( m_basicInfo.money[type] < 0 )
    {
        // 不应该走到这里
        m_basicInfo.money[type] = 0;
    }

    // 更新center上的货币
    std::vector<s64> upmoney;
    for( int t=commonproto::E_MoneyType_1; t<commonproto::E_MoneyType_Count; ++t )
    {
        if( type == t )
        {
            upmoney.push_back( count );
        }
        else
        {
            upmoney.push_back( 0 );
        }
    }
    CHall::Instance().UpdateUserMoney( UserId(), upmoney, reason );
    
    LOG_INFO( "[%s][%s][%d] userid[%llu] update[%d][%lld] old[%lld] reason[%d]", 
        __FILE__, __FUNCTION__, __LINE__,
        UserId(), type, count, old, reason );
}

void CPlayerBase::DoUpdateMoney(s32 type, s64 count)
{
    if( type < 0 || type >= commonproto::E_MoneyType_Count )
    {
        LOG_ERROR( "[%s][%s][%d] userid[%llu] update[%d][%lld]", 
            __FILE__, __FUNCTION__, __LINE__,
            UserId(), type, count );
        return;
    }

    s64 old = m_basicInfo.money[type];
    LOG_INFO( "[%s][%s][%d] userid[%llu] update[%d][%lld] old[%lld]", 
        __FILE__, __FUNCTION__, __LINE__, UserId(), type, count, old );
    m_basicInfo.money[type] += count;
    if( m_basicInfo.money[type] < 0 )
    {
        // 不应该走到这里
        m_basicInfo.money[type] = 0;
    }
}

s64 CPlayerBase::GetMoney(s32 type)
{
    if( type < 0 || type >= commonproto::E_MoneyType_Count )
    {
	    LOG_ERROR( "[%s][%s][%d] userid[%llu] get[%d]", 
            __FILE__, __FUNCTION__, __LINE__,
            UserId(), type );
        return 0;
    }
    return m_basicInfo.money[type];
}

publicproto::ActivityData* CPlayerBase::GetActivityData(s32 aid)
{
    std::map<s32, publicproto::ActivityData>::iterator it = m_activityData.find( aid );
    if( it != m_activityData.end() )
    {
        return &(it->second);
    }
    return NULL;
}

const unsigned int ACTIVITY_PROGRESS_PAGE = 100;
void CPlayerBase::InitActivityData(std::vector<publicproto::ActivityData> &adata, bool isend)
{
    std::vector<publicproto::ActivityData>::iterator it = adata.begin();
    for( ; it != adata.end(); ++it )
    {
        m_activityData[ it->activityid ] = *it;
        m_dirtyData[ it->activityid ] = 0;
    }

    if( isend )
    {
        // 初始化活动数据

        commonproto::SCActivityProgressNtf ntf;

        std::map<s32, ActivityItem>::const_iterator it = CActivityConfigManager::Instance().GetAllActivity().begin();
        for( ; it != CActivityConfigManager::Instance().GetAllActivity().end(); ++it )
        {
            bool dirtyflag = false;
            publicproto::ActivityData *data = GetActivityData( it->first );
            if( !data )
            {
                // 可能是个新活动，导致玩家没有活动数据, 增加上去
                data = _InitNewActivity( it->second );
                SELF_ASSERT( data, continue; );
                dirtyflag = true;
            }
            // 活动数据初始化
            bool ret = CHall::Instance().InitActivityData( *this, it->second, data );
            if( dirtyflag ) ret = true;
            m_dirtyData[ it->first ] = ret ? 1 : 0;

	        LOG_DEBUG( "[%s][%s][%d] userid[%llu] activity[%d] data[%d,%d,%d,%d,%lld,%lld,%lld,%lld]uptime[%llu] ret[%d]", 
                __FILE__, __FUNCTION__, __LINE__, UserId(), it->first,
                data->param1, data->param2, data->param3, data->param4,
                data->param5, data->param6, data->param7, data->param8, data->uptime, ret?1:0 );
        
            commonproto::ActivityProgress pg;
            pg.data = *data;
            pg.state = CHall::Instance().CheckActivityState( it->second, data );
            it->second.DumpConditions(pg.condition);
            ntf.progress.push_back( pg );
            if( ntf.progress.size() > ACTIVITY_PROGRESS_PAGE )
            {
                SendMsg( commonproto::SC_ACTIVITY_PROGRESS_NTF, ntf );
                ntf.progress.clear();
            }
        }
        
        if( ntf.progress.size() > 0 )
        {
            SendMsg( commonproto::SC_ACTIVITY_PROGRESS_NTF, ntf );
        }
    }
}

void CPlayerBase::NotifyActivityProgress()
{
    commonproto::SCActivityProgressNtf ntf;
    std::map<s32, publicproto::ActivityData>::iterator it = m_activityData.begin();
    for( ; it != m_activityData.end(); ++it )
    {
        ActivityItem *item = CActivityConfigManager::Instance().FindActivity( it->first );
        if( !item ) continue;

        commonproto::ActivityProgress pg;
        pg.data = it->second;
        pg.state = CHall::Instance().CheckActivityState( *item, &(it->second) );
        item->DumpConditions(pg.condition);
        ntf.progress.push_back( pg );
        if( ntf.progress.size() > ACTIVITY_PROGRESS_PAGE )
        {
            SendMsg( commonproto::SC_ACTIVITY_PROGRESS_NTF, ntf );
            ntf.progress.clear();
        }
    }
    if( ntf.progress.size() > 0 )
    {
        SendMsg( commonproto::SC_ACTIVITY_PROGRESS_NTF, ntf );
    }
}

void CPlayerBase::InitItems(std::vector<publicproto::ItemInfo> &items, bool isend)
{
    std::vector<publicproto::ItemInfo>::iterator it = items.begin();
    for( ; it != items.end(); ++it )
    {
        m_items[ it->id ] = *it;
        LOG_DEBUG( "[%s][%s][%d] user[%llu] item[%d,%d,%llu] isend[%d]", 
            __FILE__, __FUNCTION__, __LINE__, 
            UserId(), it->itemclass, it->id, it->data, isend?1:0 );
    }

    if( isend )
    {
        CActivityManager *actmgr = CHall::Instance().ActivityManager();
        if( actmgr )
        {
            int preuse = actmgr->GetRedis().GetUserPreUseRoomCards( UserId() );
            publicproto::ItemInfo *roomcard = GetItem( publicproto::ITEM_ID_ROOMCARD );
            if( roomcard )
            {
                LOG_INFO( "[%s][%s][%d] user[%llu] roomcard[%d,%llu]", 
                    __FILE__, __FUNCTION__, __LINE__, UserId(), preuse, roomcard->data );
                if( (u64)preuse > roomcard->data ) roomcard->data = 0;
                else roomcard->data -= preuse;
            }
        }
    }
}

void CPlayerBase::GameEndCheckActivity()
{
    std::map<s32, ActivityItem>::iterator it = CActivityConfigManager::Instance().GetAllActivity().begin();
    for( ; it != CActivityConfigManager::Instance().GetAllActivity().end(); ++it )
    {
        publicproto::ActivityData *data = GetActivityData( it->first );
        if( !data )
        {
            // 可能是个新活动，导致玩家没有活动数据, 增加上去
            data = _InitNewActivity( it->second );
            SELF_ASSERT( data, continue; );
        }

        bool ret = CHall::Instance().GameEndUpdateActivity( *this, it->second, data );
        std::map<s32, s8>::iterator dit = m_dirtyData.find( it->first );
        if( dit == m_dirtyData.end() || dit->second == 0 ) // 如果本来就是脏数据,则不需要修改
            m_dirtyData[ it->first ] = ret ? 1 : 0;

        int s = CHall::Instance().CheckActivityState( it->second, data );
        LOG_DEBUG( "[%s][%s][%d] userid[%llu] activity[%d] data[%d,%d,%d,%d,%lld,%lld,%lld,%lld]uptime[%llu] ret[%d] s[%d]", 
            __FILE__, __FUNCTION__, __LINE__, UserId(), it->first,
            data->param1, data->param2, data->param3, data->param4,
            data->param5, data->param6, data->param7, data->param8, data->uptime, ret?1:0, s );

        if( s == commonproto::E_ActivityState_Done && it->second.autoaward == 1 )
        {
            // 活动完成，发奖
            std::vector<publicproto::AwardInfo> awards;
            CActivityConfigManager::Instance().GetAwards( it->second, awards );
            std::vector<publicproto::AwardInfo>::iterator _it = awards.begin();
            for( ; _it != awards.end(); ++_it )
            {
                AddAward( _it->type, _it->val, _it->count, _it->reserve, 1011, it->first, CHall::Instance().GameId() );
            }

            // 发奖完成
            CHall::Instance().GetActivityAwardDone( it->second, data );

            // 消息通知
            commonproto::SCGetActivityAwardRsp rsp;
            rsp.result = errorcode::E_ErrorCode_Success;
            rsp.activityid = it->first;
            rsp.awards = awards;
            rsp.progress.state = CHall::Instance().CheckActivityState( it->second, data );
            rsp.progress.data = *data;
            SendMsg( commonproto::SC_GET_ACTIVITY_AWARD_RSP, rsp );
        }
        else if( s == commonproto::E_ActivityState_Done
                || s == commonproto::E_ActivityState_Going 
                || s == commonproto::E_ActivityState_AwardDone )
        {
            // 进度通知
            commonproto::ActivityProgress pg;
            pg.data = *data;
            pg.state = s;
            commonproto::SCActivityProgressNtf ntf;
            ntf.progress.push_back( pg );
            SendMsg( commonproto::SC_ACTIVITY_PROGRESS_NTF, ntf );
        }
        {
            // 活动奖励已完成，或进度没有变化
        }
    }
}

void CPlayerBase::GameWin(s32 iswin, s64 windata)
{
    if( iswin == STATE_LOST )
    {
        m_gamedata.lostcount += 1;
        PushGameEndData( -1 );
    }
    else if( iswin == STATE_DRAW )
    {
        m_gamedata.drawcount += 1;
        PushGameEndData( 0 );
    }
    else
    {
        m_gamedata.wincount += 1;
        PushGameEndData( 1 );

        //if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Friend )
        {
            // 日赢钱统计
            UpdateWinMoneyData( windata, false );
        }
    }

    // 输赢分统计
    if( windata > 0 )
    {
        m_gamedata.winscore += windata;
    }
    else
    {
        m_gamedata.lostscore += windata;
    }

    if( CHallConfig::Instance().GetCfg().roomMode == E_RoomMode_Friend )
    {
        m_gamedata.tfwincount += 1;

        // 好友局单局日志
        CHall::Instance().LogFriendGameData( *this, windata );
    }
}

void CPlayerBase::FlushUserActivityData()
{
    std::map<s32, publicproto::ActivityData>::iterator it = m_activityData.begin();
    for( ; it != m_activityData.end(); ++it )
    {
        if( m_dirtyData[it->first] == 1 )
        {
            FlushUserActivityData2DB( it->first );
        }
    }
}

void CPlayerBase::FlushUserGameData()
{
    dbcommon::GameDBProxyUpdateUserData m;
    m.userid = UserId();
    m.gameid = CHall::Instance().GameId();
    m.roommode = CHallConfig::Instance().GetCfg().roomMode;
    m.wincount = m_gamedata.wincount;
    m.lostcount = m_gamedata.lostcount;
    m.drawcount = m_gamedata.drawcount;
    m.winscore = m_gamedata.winscore;
    m.lostscore = m_gamedata.lostscore;
    bool ret = CHall::Instance().SendMsg2DBProxy( dbcommon::GAME_DBPROXY_UPDATE_USER_DATA, m, UserId() );
    LOG_INFO( "[%s][%s][%d] user[%llu] gamedata[%llu,%llu,%llu] score[%lld,%lld] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, UserId(), 
        m.wincount, m.lostcount, m.drawcount, 
        m.winscore, m.lostscore, ret?1:0 );
}

void CPlayerBase::FlushUserActivityData2DB(s32 activityid)
{
    publicproto::ActivityData *adata = GetActivityData( activityid );
    if( adata )
    {
        FlushUserActivityData2DB( *adata );
    }
    else
    {
        LOG_ERROR( "[%s][%s][%d] user[%llu] activityid[%d]", 
		    __FILE__, __FUNCTION__, __LINE__, UserId(), activityid );
    }
}

void CPlayerBase::FlushUserActivityData2DB(publicproto::ActivityData &data)
{
    dbcommon::GameDBProxyUpdateActivityData m;
    m.userid = UserId();
    m.activityid = data.activityid;
    m.gameid = data.gameid;
    m.param1 = data.param1;
    m.param2 = data.param2;
    m.param3 = data.param3;
    m.param4 = data.param4;
    m.param5 = data.param5;
    m.param6 = data.param6;
    m.param7 = data.param7;
    m.param8 = data.param8;
    m.uptime = GetStrTime( data.uptime );
    bool ret = CHall::Instance().SendMsg2DBProxy( dbcommon::GAME_DBPROXY_UPDATE_ACTIVITY_DATA, m, UserId() );
    LOG_INFO( "[%s][%s][%d] user[%llu] activityid[%d] param[%d,%d,%d,%d][%lld,%lld,%lld,%lld]uptime[%llu] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, UserId(), data.activityid, 
        m.param1, m.param2, m.param3, m.param4,
        m.param5, m.param6, m.param7, m.param8, data.uptime, ret?1:0 );

    if( ret )
    {
        m_dirtyData[m.activityid] = 0;
    }
}

void CPlayerBase::GetActivityAward(s32 activityid)
{
    commonproto::SCGetActivityAwardRsp rsp;
    rsp.result = errorcode::E_ErrorCode_Success;
    rsp.activityid = activityid; 
    do
    {
        publicproto::ActivityData *data = GetActivityData( activityid );
        ActivityItem *item = CActivityConfigManager::Instance().FindActivity( activityid );
        if( !data || !item )
        {
            rsp.result = errorcode::E_ErrorCode_NotFoundActivity;
            break;
        }
        
        int state = CHall::Instance().CheckActivityState( *item, data );
        if( state == commonproto::E_ActivityState_Going )
        {
            rsp.result = errorcode::E_ErrorCode_ActivityNotDone;
            break;
        }
        if( state == commonproto::E_ActivityState_AwardDone )
        {
            rsp.result = errorcode::E_ErrorCode_ActivityAwardDone;
            break;
        }

        // 可以领奖
        std::vector<publicproto::AwardInfo> awards;
        CActivityConfigManager::Instance().GetAwards( *item, awards );
        std::vector<publicproto::AwardInfo>::iterator _it = awards.begin();
        for( ; _it != awards.end(); ++_it )
        {
            AddAward( _it->type, _it->val, _it->count, _it->reserve, 1011, activityid, CHall::Instance().GameId() );
        }

        // 发奖完成
        CHall::Instance().GetActivityAwardDone( *item, data );
        
        LOG_DEBUG( "[%s][%s][%d] userid[%llu] activity[%d] data[%d,%d,%d,%d,%lld,%lld,%lld,%lld]", 
            __FILE__, __FUNCTION__, __LINE__, UserId(), activityid,
            data->param1, data->param2, data->param3, data->param4,
            data->param5, data->param6, data->param7, data->param8 );
        
        rsp.awards = awards;
        rsp.progress.state = CHall::Instance().CheckActivityState( *item, data );
        rsp.progress.data = *data;
    } while(0);

    SendMsg( commonproto::SC_GET_ACTIVITY_AWARD_RSP, rsp );
}

publicproto::ItemInfo* CPlayerBase::GetItem(s32 itemid)
{
    std::map<s32, publicproto::ItemInfo>::iterator it = m_items.find( itemid );
    if( it != m_items.end() )
    {
        return &(it->second);
    }
    return NULL;
}

void CPlayerBase::UpdateItemData(s32 id, s32 itemclass, s32 data, s32 from, s32 param1, s32 param2)
{
    publicproto::ItemInfo *item = GetItem( id );
    publicproto::ItemInfo it;
    s32 incdata = data;
    if( !item )
    {
        // 新加道具
        SELF_ASSERT( data > 0, return;);
        it.itemclass = itemclass;
        it.id = id;
        if( publicproto::ITEMCLASS_TYPE_TIME == itemclass )
        {
            it.data = TIME_NOW + data * 3600;
        }
        else if( publicproto::ITEMCLASS_TYPE_NUMBER == itemclass )
        {
            it.data = data;
        }
        m_items[ id ] = it;
        item = &it;
    }
    else
    {
        SELF_ASSERT( itemclass == item->itemclass, return; );
        if( publicproto::ITEMCLASS_TYPE_TIME == itemclass )
        {
            SELF_ASSERT( data > 0, return;);
            item->data += data * 3600;
        }
        else if( publicproto::ITEMCLASS_TYPE_NUMBER == itemclass )
        {
            s32 tmp = item->data + data;
            SELF_ASSERT( tmp >= 0, return;);
            item->data = tmp;
        }
    }
    
    dbcommon::GameDBProxyUpdateItems m;
    m.userid = UserId();
    m.itemclass = item->itemclass;
    m.id = item->id;
    if( publicproto::ITEMCLASS_TYPE_TIME == itemclass )
    {
        m.expiretime = GetStrTime(item->data);
    }
    else
    {
        m.count = item->data;
    }
    m.inccount = incdata;
    m.uptype = 2; // 增量更新
    m.from = from;
    m.param1 = param1;
    m.param2 = param2;
    bool ret = CHall::Instance().SendMsg2DBProxy( dbcommon::GAME_DBPROXY_UPDATE_ITEMS, m, UserId() );
    LOG_INFO( "[%s][%s][%d] user[%llu] itemid[%d] itemclass[%d] data[%d] sendret[%d] from[%d] param[%d,%d]", 
        __FILE__, __FUNCTION__, __LINE__, UserId(), id, itemclass, data, ret?1:0,
        m.from, m.param1, m.param2 );
}

void CPlayerBase::AddAward(s32 type, s32 val, s32 count, s32 reserve, s32 reason, s32 param1, s32 param2)
{
    switch( type )
    {
    case commonproto::E_MoneyType_1:
    case commonproto::E_MoneyType_2:
    case commonproto::E_MoneyType_3:
    case commonproto::E_MoneyType_4:
    case commonproto::E_MoneyType_5:
        UpdateMoney( type, count, reason );
        break;
    case commonproto::E_AwardType_Item:
        {
            s32 id = val;
            s32 itemclass = (reserve > 0) ? publicproto::ITEMCLASS_TYPE_TIME : publicproto::ITEMCLASS_TYPE_NUMBER;
            s32 data = count;
            if( itemclass == publicproto::ITEMCLASS_TYPE_TIME )
            {
                data = reserve;
            }
            UpdateItemData( id, itemclass, data, reason, param1, param2 );
        }
        break;
    default:
        LOG_ERROR( "[%s][%s][%d] user[%llu] award[%d,%d,%d,%d] reason[%d]. unknown type", 
            __FILE__, __FUNCTION__, __LINE__, UserId(), type, val, count, reserve, reason );
        break;
    };
    LOG_DEBUG( "[%s][%s][%d] user[%llu] award[%d,%d,%d,%d] reason[%d]", 
        __FILE__, __FUNCTION__, __LINE__, UserId(), type, val, count, reserve, reason );
}

void CPlayerBase::UpdateWinMoneyData(s64 data, bool force)
{
    bool up = force;
    s32 now = GetCurDay();
    if( now != m_getDate )
    {
        // 不是同一天数据更新回去
        up = true;
    }
    else
    {
        if( !force )
        {
            m_winData += data;
            ++m_winCount;
        }
    }
    LOG_DEBUG( "[%s][%s][%d] user[%llu] data[%lld] winData[%lld] up[%d] now[%d] m_getDate[%d] wincount[%d]", 
        __FILE__, __FUNCTION__, __LINE__, UserId(), data, m_winData, up?1:0, now, m_getDate, m_winCount );

    if( up && (m_winData > 0 || m_winCount > 0) )
    {
        dbcommon::GameDBProxyUpdateWinMoneyData m;
        m.userid = UserId();
        m.gameid = CHall::Instance().GameId();
        m.windata = m_winData;
        m.wincount = m_winCount;
        m.roommode = CHallConfig::Instance().GetCfg().roomMode;
        m.getdate = m_getDate; 
        bool ret = CHall::Instance().SendLogMsg2DBProxy( 
            dbcommon::GAME_DBPROXY_UPDATE_WIN_MONEY_DATA, m, UserId() );
        LOG_INFO( "[%s][%s][%d] user[%llu] data[%d,%lld,%d,%d] sendret[%d] roommode[%d]", 
            __FILE__, __FUNCTION__, __LINE__, UserId(), 
            m.gameid, m.windata, m.wincount, m.getdate, ret?1:0, m.roommode );

        m_winData = 0;
        m_winCount = 0;
    }
    if( !force && now != m_getDate )
    {
        m_winData = data;
        m_winCount = 1;
        m_getDate = now;
    }
}

void CPlayerBase::CacheHandCard(unsigned char card)
{
    if( m_handcards.size() == 0 )
    {
        HandCard hc;
        m_handcards.push_back( hc );
    }
    m_handcards[0]._cards.push_back( card );
}

void CPlayerBase::CacheHandCards(char *cards, int count, char type)
{
    HandCard hc;
    hc._type = type;
    for( int i=0; i<count; ++i )
        hc._cards.push_back( cards[i] );
    m_handcards.push_back( hc );
}

void CPlayerBase::_CopyDBUserBasicInfo(dbcommon::DBUserBasicInfo &basicinfo)
{
    m_basicInfo.userid = UserId();
    m_basicInfo.headid = basicinfo.headid;
    m_basicInfo.headurl = basicinfo.headurl;
    m_basicInfo.nickname = basicinfo.nickname;
    m_basicInfo.sex = basicinfo.sex;
    m_basicInfo.money.clear();
    m_basicInfo.money.push_back( basicinfo.money1 );
    m_basicInfo.money.push_back( basicinfo.money2 );
    m_basicInfo.money.push_back( basicinfo.money3 );
    m_basicInfo.money.push_back( basicinfo.money4 );
    m_basicInfo.money.push_back( basicinfo.money5 );
    m_basicInfo.level = basicinfo.level;
    m_basicInfo.exp = basicinfo.exp;
    m_basicInfo.uuid = basicinfo.uuid;
    m_basicInfo.utype = basicinfo.type;
    m_type = basicinfo.type;

    SetCurScore(0);
    SetAllScore(0);
}

void CPlayerBase::_DumpUserInfo(std::string &data)
{
    char buf[1024] = {0};
    int len = m_basicInfo.SerializeToArray( buf, sizeof(buf) );
    SELF_ASSERT( len != IMessage::E_Error, return; );
    data.append( buf, len );
}

publicproto::ActivityData* CPlayerBase::_InitNewActivity(const ActivityItem &config)
{
    publicproto::ActivityData adata;
    adata.activityid = config.activityid;
    adata.gameid = config.gameid;
    adata.param1 = 0;
    adata.param2 = 0;
    adata.param3 = 0;
    adata.param4 = 0;
    adata.param5 = 0;
    adata.param6 = 0;
    adata.param7 = 0;
    adata.param8 = 0;
    adata.uptime = TIME_NOW;

    m_activityData[ adata.activityid ] = adata;
    m_dirtyData[ adata.activityid ] = 0;
    return &(m_activityData[ adata.activityid ]);
}

void CPlayerBase::_TimeOutAgreeDismissFriendRoom()
{
    CRoomBase *room = GetRoom();
    if( room )
    {
        s32 agree = IsOffline() ? 1 : 0;
        LOG_DEBUG( "[%s][%s][%d] user[%llu] agree[%d] timeout agree dismiss", 
            __FILE__, __FUNCTION__, __LINE__, UserId(), agree );
        // 解散选择超时时 玩家在线则默认不同意，否则默认同意
        room->AgreeDismissFriendRoom( *this, agree, true );
    }
}


